Skip to content

path: remove StringPrototypeCharCodeAt from more posix methods#63662

Open
whoekage wants to merge 1 commit into
nodejs:mainfrom
whoekage:perf/path-posix-indexing-extend
Open

path: remove StringPrototypeCharCodeAt from more posix methods#63662
whoekage wants to merge 1 commit into
nodejs:mainfrom
whoekage:perf/path-posix-indexing-extend

Conversation

@whoekage
Copy link
Copy Markdown

Summary

Extends the optimization landed in #54546 (posix.extname) to the remaining POSIX path methods still using StringPrototypeCharCodeAt. #54668 covers resolve/normalize/parse; this PR covers dirname, basename, and relative.

What changed

Replaced StringPrototypeCharCodeAt(path, i) === CHAR_FORWARD_SLASH with path[i] === '/' in three POSIX methods. Diff: +12 / βˆ’14 lines in lib/path.js.

Benchmark

Apple M1, 30 runs via benchmark/compare.js. Showing significant cases:

dirname-posix

path delta sig
/foo +12.45% ***
/foo/bar/baz/asdf/quux +8.82% ***
/foo/bar +8.82% ***
foo +6.34% *
foo/bar +2.26% *

basename-posix

pathext delta sig
/foo/bar/baz/asdf/quux.html|.html +8.38% ***
/foo/.bar.baz|.baz +8.25% ***
/foo/.bar.baz +6.90% ***
foo/bar. +5.94% ***
foo +5.78% *

relative-posix

paths delta sig
/var|/bin +3.28% **

Methodology validation

Control benchmark on extname-posix (unchanged in this PR) shows Β±2% deltas without statistical significance, confirming methodology. No regressions on Win32 paths (slow path untouched).

Test plan

  • parallel/test-path* β€” all 17 pass
  • parallel/test-url-* β€” all 15 pass
  • parallel/test-fs-readfile/stat/realpath β€” pass
  • parallel/test-module-* β€” all 32 pass
  • Fuzz: 425 input cases identical to baseline
  • make lint-js β€” clean

Refs: #54546, #54668

Extends the optimization applied to posix.extname in nodejs#54546 to
posix.dirname, posix.basename, and posix.relative. nodejs#54668 covers
posix.resolve, posix.normalize, and posix.parse.

Replacing `StringPrototypeCharCodeAt(path, i) === CHAR_FORWARD_SLASH`
with `path[i] === '/'` is consistently faster on V8 because the
single-character string comparison hits a faster path than the
integer comparison after charCodeAt().

Benchmark (Apple M1, 30 runs via benchmark/compare.js):

  dirname-posix:
    path='/foo'                                  +12.45% ***
    path='/foo/bar/baz/asdf/quux'                 +8.82% ***
    path='/foo/bar'                               +8.82% ***
    path='foo'                                    +6.34% *
    path='foo/bar'                                +2.26% *

  basename-posix:
    pathext='/foo/bar/baz/asdf/quux.html|.html'   +8.38% ***
    pathext='/foo/.bar.baz|.baz'                  +8.25% ***
    pathext='/foo/.bar.baz'                       +6.90% ***
    pathext='foo/bar.'                            +5.94% ***
    pathext='foo'                                 +5.78% *

  relative-posix:
    paths='/var|/bin'                             +3.28% **

No regressions in Win32 paths (slow path untouched). Control
benchmark on extname (unchanged) shows Β±2% noise without
significance, confirming methodology.
@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/path

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. path Issues and PRs related to the path subsystem. labels May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. path Issues and PRs related to the path subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants